/**
 Copyright (C) 2013 Yuyao Liang

 This source code is release under the BSD License.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.

 Created on Nov 12, 2013 9:28:19 PM
 */
package com.googlecode.backtest.controller;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.googlecode.backtest.dataset.IBackTestStockDataset;
import com.googlecode.backtest.dataset.manager.BackTestDataManager;
import com.googlecode.backtest.dataset.manager.IDataManager;
import com.googlecode.backtest.dataset.provider.IDataProvider;
import com.googlecode.backtest.document.IBackTestContent;
import com.googlecode.backtest.document.Item;
import com.googlecode.backtest.document.Messages;
import com.googlecode.backtest.rule.IAlgorithm;
import com.googlecode.backtest.rule.ISourceAlgorithm;
import com.googlecode.backtest.rule.ITAParameters;
import com.googlecode.backtest.rule.queue.IAlgorithmQueue;
import com.googlecode.backtest.rule.ta.Input_Algorithm;

/**
 * @author lianyuy
 * 
 */
public class BackTestController
		implements
		IBackTestController<IBackTestStockDataset, ITAParameters, IAlgorithm<IBackTestStockDataset, ITAParameters>> {
	private final String ID = getClass().getName();
	private final String Version = Messages
			.getString("BackTestController.VERSION");
	protected Map<String, IBackTestStockDataset> map = new HashMap<String, IBackTestStockDataset>();
	protected IDataProvider<IBackTestStockDataset> provider = null;
	protected IDataManager manager = null;
	protected IBackTestContent<Item> content;

	/**
	 * 
	 * @param content
	 */
	public BackTestController(IBackTestContent<Item> content) {
		super();
		this.content = content;
		this.manager = new BackTestDataManager(this);
		findProvider(content);
		this.manager.parseContent(content);
	}

	/**
	 * @param content
	 */
	private void findProvider(IBackTestContent<Item> content) {
		this.provider = content.getProvider();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.srclib.base.IDable#getID()
	 */
	@Override
	public String getID() {
		return ID;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.srclib.base.Versionable#getVersion()
	 */
	@Override
	public String getVersion() {
		return Version;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.googlecode.backtest.controller.IBackTestController#runAlgorithm(java
	 * .lang.Class, T[], java.lang.Object)
	 */
	@SuppressWarnings("rawtypes")
	@Override
	public IBackTestStockDataset runAlgorithm(
			Class<IAlgorithm<IBackTestStockDataset, ITAParameters>> algorithmclass,
			IConstructorArguments arguments, List<String> dataids,
			ITAParameters parameter) {

		try {
			Constructor[] cs = algorithmclass.getConstructors();
			Object[] args = new Object[] { arguments.getGUID(), dataids };
			Class[] paramTypes;
			Method method;
			Object o;
			Object instance = cs[0].newInstance(args);

			if (instance instanceof Input_Algorithm) {
				paramTypes = new Class[] { IDataProvider.class };
				method = instance.getClass().getMethod("setDataProvider",
						paramTypes);
				args = new Object[] { getProvider() };
				o = method.invoke(instance, args);
			}

			List<IBackTestStockDataset> dataset = new ArrayList<IBackTestStockDataset>();
			for (String id : dataids) {
				dataset.add((IBackTestStockDataset) manager.getData(id));
			}

			paramTypes = new Class[] { List.class, ITAParameters.class };
			method = instance.getClass().getMethod("calculate", paramTypes);
			args = new Object[] { dataset, parameter };
			o = method.invoke(instance, args);
			Boolean ret = (Boolean) o;
			if (ret.booleanValue()) {
				paramTypes = new Class[] {};
				method = instance.getClass().getMethod("getResult", paramTypes);
				args = new Object[] {};
				o = method.invoke(instance, args);
				IBackTestStockDataset result = (IBackTestStockDataset) o;
				manager.putData(((IAlgorithm) instance).getGUID(), result);
				return result;
			}
			return null;

		} catch (Exception e) {
			e.printStackTrace();
		}

		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.googlecode.backtest.controller.IBackTestController#runAlgorithmQueue
	 * (java.lang.Class, T[], java.lang.Object)
	 */
	@Override
	public IBackTestStockDataset runAlgorithmQueue(
			Class<IAlgorithmQueue<IBackTestStockDataset, ITAParameters, IAlgorithm<IBackTestStockDataset, ITAParameters>>> algorithmqueueclass,
			List<String> dataids, ITAParameters parameter) {
		// TODO Auto-generated method stub
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.googlecode.backtest.controller.IBackTestController#getProvider()
	 */
	@Override
	public IDataProvider<IBackTestStockDataset> getProvider() {
		return provider;
	}

	/**
	 * @return the manager
	 */
	public IDataManager getManager() {
		return manager;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public void start() {
		List<ISourceAlgorithm> sourcelist = manager.getSourceList();
		Iterator<ISourceAlgorithm> iter = sourcelist.iterator();
		while (iter.hasNext()) {
			ISourceAlgorithm source = iter.next();
			source.setDataProvider(provider);
			if (source.run()) {
				Object result = source.getResult();
				if (result != null) {
					manager.putData(source.getGUID(), result);
				}
			}
		}
		System.out.println(content.getID());
	}
}
